package com.github.natholdallas.controller

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.github.natholdallas.common.Role
import com.github.natholdallas.database.*
import org.springframework.boot.jackson.JsonComponent
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort

data class PageIn(
    val page: Int = 1,
    val size: Int = 20
) : PageRequest(page - 1, size, Sort.unsorted())


data class LoginIn(
    val username: String,
    val password: String
)


data class LoginToken(
    val role: Role
)


typealias SerializerFunc<T> = (v: T, g: JsonGenerator) -> Unit

inline fun <T> start(v: T?, g: JsonGenerator?, func: SerializerFunc<T>) {
    if (v !== null && g !== null) {
        g.writeStartObject()
        func(v, g)
        g.writeEndObject()
    }
}

inline fun <T : LongIdTableModel> startWithLongIdTable(v: T?, g: JsonGenerator?, func: SerializerFunc<T>) {
    if (v !== null && g !== null) {
        g.writeStartObject()
        v.id?.let { g.writeNumberField("id", it) }
        func(v, g)
        g.writeEndObject()
    }
}

inline fun <T : LongIdRecordModel> startWithLongIdRecord(v: T?, g: JsonGenerator?, func: SerializerFunc<T>) {
    if (v !== null && g !== null) {
        g.writeStartObject()
        v.id?.let { g.writeNumberField("id", it) }
        g.writeNumberField("createTime", v.createTime)
        g.writeNumberField("updateTime", v.updateTime)
        func(v, g)
        g.writeEndObject()
    }
}

fun <T> JsonGenerator.writeArrayField(fieldName: String, array: Collection<T>) {
    writeArrayFieldStart(fieldName)
    array.forEach(::writeObject)
    writeEndArray()
}


@JsonComponent
class PageSerializer<T> : JsonSerializer<Page<T>>() {
    override fun serialize(value: Page<T>?, gen: JsonGenerator?, serializers: SerializerProvider?) =
        start(value, gen) { v, g ->
            g.writeNumberField("total", v.totalElements)
            g.writeNumberField("pages", v.totalPages)
            g.writeArrayField("content", v.content)
        }
}


@JsonComponent
class CommentSerializer : JsonSerializer<CommentTable>() {
    override fun serialize(value: CommentTable?, gen: JsonGenerator?, serializers: SerializerProvider?) {
        startWithLongIdRecord(value, gen) { v, g ->
            g.writeNumberField("copilot", v.copilot.id!!)
            g.writeNumberField("userId", v.user.id!!)
            g.writeObjectField("user", v.user)
            g.writeStringField("content", v.content)
        }
    }
}


class TinyUserSerializer : JsonSerializer<User>() {
    override fun serialize(value: User?, gen: JsonGenerator?, serializers: SerializerProvider?) {
        startWithLongIdTable(value, gen) { v, g ->
            g.writeStringField("name", v.name)
        }
    }
}


@JsonComponent
class UserSerializer : JsonSerializer<User>() {
    override fun serialize(value: User?, gen: JsonGenerator?, serializers: SerializerProvider?) {
        startWithLongIdRecord(value, gen) { v, g ->
            g.writeStringField("username", v.username)
            g.writeStringField("password", v.password)
            g.writeNumberField("role", v.role.ordinal)
            g.writeStringField("name", v.name)
            g.writeStringField("avatar", v.avatar)

            when (v.role) {
                Role.USER -> {
                    g.writeNumberField("amount", v.amount)
                    g.writeNumberField("balance", v.balance)
                }

                Role.COPILOT -> {
                    g.writeStringField("description", v.description)
                    g.writeNumberField("gender", v.gender.ordinal)
                    g.writeStringField("phone", v.phone)
                    g.writeStringField("qrcode", v.qrcode)
                    g.writeStringField("tag", v.tag)
                }

                else -> {}
            }
        }
    }
}

@JsonComponent
class TopupSerializer : JsonSerializer<TopupTable>() {
    override fun serialize(value: TopupTable?, gen: JsonGenerator?, serializers: SerializerProvider?) {
        startWithLongIdRecord(value, gen) { v, g ->
            g.writeNumberField("user", v.user.id!!)
            g.writeStringField("description", v.description)
            g.writeNumberField("amount", v.amount)
            g.writeNumberField("gift", v.gift)
            g.writeBooleanField("payment", v.payment)
            g.writeNumberField("amountRecord", v.amountRecord)
            g.writeNumberField("balanceRecord", v.balanceRecord)
        }
    }
}


@JsonComponent
class OrderSerializer : JsonSerializer<OrderTable>() {
    override fun serialize(value: OrderTable?, gen: JsonGenerator?, serializers: SerializerProvider?) {
        startWithLongIdRecord(value, gen) { v, g ->
            g.writeNumberField("user", v.user.id!!)
            g.writeNumberField("copilot", v.copilot.id!!)
            g.writeStringField("description", v.description)
            g.writeBooleanField("payment", v.payment)
            g.writeNumberField("type", v.type.ordinal)
            g.writeNumberField("price", v.price)
            g.writeNumberField("duration", v.duration)
            g.writeNumberField("totalPrice", v.totalPrice)
            g.writeNumberField("iPrice", v.iPrice)
            g.writeNumberField("cPrice", v.cPrice)
            g.writeNumberField("amountRecord", v.amountRecord)
            g.writeNumberField("balanceRecord", v.balanceRecord)
        }
    }
}
